package com.cefetmg.mmc.mrcpsp.process.impl;

import java.io.File;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;

import com.cefetmg.mmc.mrcpsp.model.enums.EnumExecutionTypes;
import com.cefetmg.mmc.mrcpsp.process.ExecutionTypeProcessor;
import com.cefetmg.mmc.mrcpsp.process.MmProcessor;
import com.cefetmg.mmc.mrcpsp.process.ResultsProcessor;
import com.cefetmg.mmc.mrcpsp.process.concurrent.MrcpspWorkerPool;
import com.cefetmg.mmc.mrcpsp.utils.ChronoWatch;
import com.cefetmg.mmc.mrcpsp.utils.FileUtils;
import com.cefetmg.mmc.mrcpsp.utils.LogUtils;
import com.cefetmg.mmc.mrcpsp.utils.PropertyConstants;
import com.cefetmg.mmc.mrcpsp.utils.PropertyManager;
import com.cefetmg.mmc.mrcpsp.utils.SystemUtils;
import com.cefetmg.mmc.mrcpsp.utils.UrlUtils;

public class ExecutionTypeProcessorImpl implements ExecutionTypeProcessor {

	private static final Logger log = Logger.getLogger(MmProcessorImpl.class);
	private ResultsProcessor resultsProcessor;
	private MmProcessor mmProcessor;
	
	@Override
	public void execute() {
		PropertyManager.getInstance();		
		String executionType = UrlUtils.getInstance().getExecutionType();
		String hasThread = UrlUtils.getInstance().getBooleanThread();
		
		removeOldResultFiles();
		
		if (StringUtils.equals(executionType, EnumExecutionTypes.ONE_FILE.getName())) {		
			executeOneFile();
		} else if (StringUtils.equals(executionType, EnumExecutionTypes.ONE_FILE_TIMES.getName())) {
			executeOneFileTimes();
		} else if (StringUtils.equals(executionType, EnumExecutionTypes.ALL.getName())) {
			
			if (StringUtils.equals(hasThread, "true")) {
				executeAllFilesConcurrent();
			} else {
				executeAllFiles();
			}
			
		} else if (StringUtils.equals(executionType, EnumExecutionTypes.ALL_TIMES.getName())) {
			
			if (StringUtils.equals(hasThread, "true")) {
				executeAllFilesConcurrent();
			} else {
				executeAllFilesTimes();
			}
			
		} else {
			log.log(Level.ERROR, "Argument not supported!" + LogUtils.generateErrorLog(Thread.currentThread().getStackTrace()));
			throw new IllegalArgumentException("Argument not supported!" + LogUtils.generateErrorLog(Thread.currentThread().getStackTrace()));
		}	
		
	}

	@Override
	public void executeOneFile() {
		//start
		ChronoWatch watch = ChronoWatch.getInstance("MRCPSP Execution").start();
		String fileName = PropertyManager.getInstance().getProperty(PropertyConstants.INSTANCE_FILE);
				
		SystemUtils.getSystemInformation();
		
		mmProcessor = new MmProcessorImpl();
		resultsProcessor = new ResultsProcessorImpl();
		mmProcessor.execute(fileName);
		
		// finish
		String timeString = watch.time();
		resultsProcessor.writeRunningTimeToResultFile(timeString, fileName);
		log.info(timeString);
	}

	@Override
	public void executeOneFileTimes() {
		//start		
		Integer timesToRun = Integer.parseInt(UrlUtils.getInstance().getExecutionTimes());
		String fileName = PropertyManager.getInstance().getProperty(PropertyConstants.INSTANCE_FILE);
				
		SystemUtils.getSystemInformation();
		
		mmProcessor = new MmProcessorImpl();
		resultsProcessor = new ResultsProcessorImpl();
		//PropertyManager.getInstance().setLog4JLevel(Level.OFF);
		
		ChronoWatch watch = ChronoWatch.getInstance("MRCPSP Execution").start();
		
		for (int i = 0; i < timesToRun; i++) {
			resultsProcessor.checkLowerMakespan(mmProcessor.execute(fileName));
		}
		
		// finish
		PropertyManager.getInstance().setLog4JLevel(Level.INFO);
		resultsProcessor.writeLowerMakespanToOneInstance(fileName);
		String timeString = watch.time();
		resultsProcessor.writeRunningTimeToResultFile(timeString, fileName);
		log.info(timeString);
	}

	@Override
	public void executeAllFiles() {		
		ChronoWatch watch = ChronoWatch.getInstance("MRCPSP Execution").start();		
		SystemUtils.getSystemInformation();
		
		mmProcessor = new MmProcessorImpl();
		resultsProcessor = new ResultsProcessorImpl();
				
		for (File file: FileUtils.getAllFilesInstances()) {		
			LogUtils.setINSTANCE_STATUS("");			
			mmProcessor.execute(file.getName());	
		}
		
		// finish
		String timeString = watch.time();
		resultsProcessor.writeRunningTimeToResultFileAllInstances(timeString);
		log.info(timeString);
	}

	@Override
	public void executeAllFilesTimes() {
		ChronoWatch watch = ChronoWatch.getInstance("MRCPSP Execution").start();
		Integer timesToRun = Integer.parseInt(UrlUtils.getInstance().getExecutionTimes());
		SystemUtils.getSystemInformation();
		
		mmProcessor = new MmProcessorImpl();
		resultsProcessor = new ResultsProcessorImpl();		
				
		for (File file: FileUtils.getAllFilesInstances()) {	
			LogUtils.setINSTANCE_STATUS("");			
			
			for (int i = 0; i < timesToRun; i++) {
				resultsProcessor.checkLowerMakespan(mmProcessor.execute(file.getName()));
			}	
			
			resultsProcessor.writeLowerMakespanToAllInstances(file.getName());
			resultsProcessor.setLowerMakespan(null);
		}
		
		// finish
		String timeString = watch.time();
		resultsProcessor.writeRunningTimeToResultFileAllInstances(timeString);
		log.info(timeString);
	}
	
	private void removeOldResultFiles() {
		FileUtils.removeAllFilesFromFolder(PropertyConstants.RESULTS_PATH);
	}

	@Override
	public void executeAllFilesConcurrent() {
		log.info("======== Executing in CONCURRENT MODE");
		MrcpspWorkerPool pool = new MrcpspWorkerPool();
		try {
			pool.executeAllFilesConcurrent();
		} catch (InterruptedException e) {					
			e.printStackTrace();
		}
	}	

}
